import rctk.audio.resources

from rctk.app import App
from rctk.audio.audiocontrol import AudioControl
from rctk.audio.file import FileChooser
from rctk.widgets import Button, StaticText, List, Panel, CheckBox
from rctk.layouts import GridLayout
from rctk.resourceregistry import BaseResource, DynamicResource, addResource
from rctk.login.simple import LoginDialog, LoginException

import os
import random

class MusicServer(DynamicResource):
    def __init__(self, player):
        super(MusicServer, self).__init__('music')
        self.player = player

    def __call__(self, elements):
        fileid = elements[-1]
        file = self.player.lib.library[int(fileid)]['file']
        if file.endswith("mp3"):
            type = "audio/mpeg"
        else:
            type = "audio/ogg"

        data=open((self.player.base + '/' + file).decode('utf-8'), "r").read()

        return BaseResource(data, fileid, type)

class Playlist(object):
    def __init__(self):
        self.current = -1
        self.counter = 0
        self.library = {}
        self.played = []
        self.toplay = []
        self.random = False
        self.loop = False

    def add(self, file):
        id = self.counter
        self.counter += 1
        self.library[id] = dict(id=id, title=file, file=file)
        self.toplay.append(id)
        return (id, file)

    def jump(self, id):
        """ user is jumping. This means shifting between toplay/played,
            or just continue being random """
        self.current = id
        if not self.random: # move the separation between played/toplay
            try:
                idx = self.toplay.index(id)
                self.played.extend(self.toplay[:idx+1])
                self.toplay = self.toplay[idx+1:]
            except ValueError, e:
                try:
                    idx = self.played.index(id)
                    self.played, self.toplay = self.played[:idx+1], self.played[idx+1:] + self.toplay
                except ValueError, e:
                    self.current = -1
                    return None
        return self.library[self.current]

    def next(self):
        if not self.toplay:
            if not self.loop:
                self.current = -1
                return None # nothing to play
            self.toplay, self.played = self.played, [] # move everything back to toplay again

        idx = 0 # top track by default
        if self.random:
            idx = random.choice(range(len(self.toplay)))
        self.current = self.toplay.pop(idx)
        self.played.append(self.current)
        return self.library[self.current]

class Player(App):
    def __init__(self, base=None, supported="ogg,mp3", userpass=None, **kw):
        self.lib = Playlist()
        self.base = base or os.getcwd()
        self._supported = supported.split(",")
        self.username, self.password = None, None
        if userpass and ':' in userpass:
            self.username, self.password = userpass.split(":", 1)
    
    def supported(self, f):
        return f[-3:].lower() in self._supported

    def relative(self, path):
        """ return a path relative to self.base """
        return path[len(self.base):]

    def add_to_library(self, dummy, dirname, fnames):
        remove = [f for f in fnames if f[0] in ":."]
        for r in remove:
            fnames.remove(r)

        for f in sorted(fnames):
            if self.supported(f):
                rel = os.path.join(self.relative(dirname), f)
                id, title = self.lib.add(rel)
                self.playlist.add(id, title)

    def load(self, path):
        os.path.walk(path, self.add_to_library, None)

    def choose(self, e):
        c = FileChooser(self.tk, title="Choose files or directories", restrict=True)
        c.open()
        c.open_directory(self.base)

        def handle_ok():
            c.close()
            c.destroy()
            for f in c.selection():
                if os.path.isdir(f):
                    self.load(f)
                elif self.supported(f):
                    rel = self.relative(f)
                    id, title = self.lib.add(rel)
                    self.playlist.add(id, title)

        c.ok_clicked = handle_ok

    def run(self, tk):
        self.tk = tk
        if self.username:
            self.login = LoginDialog(self.tk)
            self.login.verify_login = self.verify_login
        else:
            self.start_player()

    def verify_login(self, username, password):
        if self.username == username and self.password == password:
            self.login.close()
            self.login.destroy()
            self.start_player()
        else:
            raise LoginException()
        
    def start_player(self):
        self.serverid = addResource(MusicServer(self))

        root = self.tk.root()
        root.setLayout(GridLayout(columns=1, padx=1, pady=1, sticky=GridLayout.NEWS))
        self.playlist = List(self.tk, size=20, width=400)
        addfiles = Button(self.tk, "Add files..")
        addfiles.click = self.choose

        playing = StaticText(self.tk, "...")
        player = AudioControl(self.tk)
        bnext = Button(self.tk, "Next")
        bplay = Button(self.tk, "Play")
        bpause = Button(self.tk, "Pause")
        brandom = CheckBox(self.tk)
        trandom = StaticText(self.tk, "random")
        bloop = CheckBox(self.tk)
        tloop = StaticText(self.tk, "loop")

        root.append(self.playlist)
        root.append(addfiles)
        root.append(playing)
        root.append(player)

        p = Panel(self.tk)
        p.setLayout(GridLayout(rows=1))

        p.append(bnext)
        p.append(bplay)
        p.append(bpause)
        p.append(brandom)
        p.append(trandom)
        p.append(bloop)
        p.append(tloop)

        root.append(p)

        def load_and_play(track):
            player.load('resources/%s/%d' % (self.serverid, track['id']))
            playing.text = track['title']
            player.play()
            self.playlist.value = track['id']

        def next(e):
            track = self.lib.next()
            if track is None:
                return
            load_and_play(track)

        def pause(e):
            player.pause()

        def play(e):
            if self.lib.current == -1:
                next(None)
            player.play()

        def playlist_click(e):
            newtrack = self.playlist.value
            track = self.lib.jump(newtrack)
            load_and_play(track)

        def random(e):
            self.lib.random = brandom.checked

        def loop(e):
            self.lib.loop = bloop.checked

        self.playlist.click = playlist_click
        bnext.click = next
        bpause.click = pause
        bplay.click = play
        brandom.click = random
        bloop.click = loop
        player.ended = next

        root.layout()
